package com.ewei.support.mail.javax;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;

import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Part;
import javax.mail.internet.ContentType;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;
import javax.mail.internet.ParseException;

import org.budo.mail.util.MessageUtil;
import org.budo.support.lang.util.StringUtil;
import org.budo.support.slf4j.Slf4j;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.slf4j.Logger;

import net.freeutils.charset.UTF7Charset;

/**
 * @author limingwei
 * @see com.ewei.support.mail.util.MailServerUtil
 * @see com.ewei.support.javax.mail.internet.util.MimeMessageUtil
 * @see com.ewei.support.javax.mail.util.MessageUtil
 */
public class ReceiveMailUtil {
    private static final Logger log = Slf4j.getLogger();

    /**
     * 获取邮件标题,处理繁体字乱码的问题
     */
    public static String getMailSubject(Message message) {
        String subjectTraditionalCharacters = infocarePropcareGetMailSubject(message); // 繁体字乱码解决的方式获取邮件标题
        if (!StringUtil.isEmpty(subjectTraditionalCharacters)) {
            return subjectTraditionalCharacters;
        }

        return MessageUtil.getSubject(message); // 原始方式获取邮件标题, 有可能有乱码
    }

    private static String infocarePropcareGetMailSubject(Message message) {
        String replaceGB2312ToGBK = null;

        try {
            String[] subjectHeaders = message.getHeader("Subject");
            if (null == subjectHeaders || subjectHeaders.length < 1) {
                return null;
            }

            String subjectHeader = subjectHeaders[0];
            if (StringUtil.isEmpty(subjectHeader)) {
                return null;
            }

            replaceGB2312ToGBK = replaceGB2312ToGBK(subjectHeader); // decode 预处理

            return decodeText(replaceGB2312ToGBK); // 解析文本
        } catch (Throwable e) {
            throw new RuntimeException("infocarePropcareGetMailSubject error, replaceGB2312ToGBK=" + replaceGB2312ToGBK, e);
        }
    }

    /**
     * 解析文本，utf7 特殊处理
     */
    private static String decodeText(String encodedText) {
        if (null == encodedText || encodedText.isEmpty() || encodedText.trim().isEmpty()) {
            return encodedText;
        }

        try {
            if (encodedText.startsWith("?unicode-1-1-utf-7?") || encodedText.toLowerCase().startsWith("?unicode-1-1-utf-7?")) {
                byte[] bytes = encodedText.getBytes();
                ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
                UTF7Charset utf7Charset = new UTF7Charset();
                CharBuffer charBuffer = utf7Charset.decode(byteBuffer);
                return charBuffer.toString();
            }

            return MimeUtility.decodeText(encodedText);
        } catch (Throwable e) {
            log.error("encodedText=" + encodedText + ", e=" + e, e);
            return encodedText;
        }
    }

    private static String replaceGB2312ToGBK(String source) {
        if (source == null) {
            return null;
        }

        if (source.toLowerCase().indexOf("?gb2312?") != -1) {
            return source.replaceAll("\\?[gG][bB]2312\\?", "?gbk?");
        }

        return source;
    }

    /**
     * 判断是否包含乱码
     */
    public static Boolean hasMessyCode(String text) {
        if (null != text) {
            for (char ch : text.toCharArray()) {
                if (ch >= 65533) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 仅返回文本
     * @see #getHtmlMailContent(Part)
     */
    public static String getPlainTextMailContent(Part part) {
        try {
            if (part.isMimeType("text/plain")) {
                return htmlPartGetContent(part);
            }

            String plainTextMailContent = htmlPartGetContent(part); // 邮件中取得的文本
            return removeHtmlTagsByJsoup(plainTextMailContent);
        } catch (Throwable e) {
            throw new RuntimeException("getPlainTextMailContent error", e);
        }
    }

    /**
     * 返回HTML内容的邮件正文
     * @see #getPlainTextMailContent(Part)
     */
    public static String getHtmlMailContent(Part part) {
        try {
            String contentType = part.getContentType();
            StringBuffer bodyText = new StringBuffer();
            boolean contentTypeHasName = contentTypeHasName(contentType);

            if (part.isMimeType("text/plain") && !contentTypeHasName) { // plain且没有name
                log.info("#152 getHtmlMailContent, mimeType=text/plain, contentType=" + contentType);
            } else if (part.isMimeType("text/html") && !contentTypeHasName) { // html且没有name
                String htmlPartGetContent = htmlPartGetContent(part);
                bodyText.append(htmlPartGetContent);
            } else if (part.isMimeType("multipart/*")) {
                Multipart multipart = (Multipart) part.getContent();
                int counts = multipart.getCount();
                for (int i = 0; i < counts; i++) {
                    BodyPart bodyPart = multipart.getBodyPart(i);
                    String htmlMailContent = getHtmlMailContent(bodyPart); // 递归
                    bodyText.append(htmlMailContent);
                }
            } else if (part.isMimeType("message/rfc822")) {
                Part content = (Part) part.getContent();
                String htmlMailContent = getHtmlMailContent(content); // 递归
                bodyText.append(htmlMailContent);
            } else if (part.isMimeType("image/png") // 
                    || part.isMimeType("image/jpeg") // 
                    || part.isMimeType("image/gif") // 
                    || part.isMimeType("text/rfc822-headers") // 
                    || part.isMimeType("application/octet-stream") // 
                    || part.isMimeType("application/vnd.ms-excel") // 
                    || part.isMimeType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") // 
                    || part.isMimeType("message/delivery-status")) { // 
                log.info("getHtmlMailContent else 1, part={}, contentType={}", part, part.getContentType());
            } else {
                log.error("getHtmlMailContent else 2, part={}, contentType={}", part, part.getContentType());
            }

            return bodyText.toString();
        } catch (Throwable e) {
            String error = e.getMessage();
            if (StringUtil.contains(error, "Unknown encoding")) {
                log.warn("ReceiveMailUtil#getHtmlMailContent() error, e=" + e);
                return "系统: 邮件内容编码未支持 GET_HTML_MAIL_CONTENT_UNKNOWN_ENCODING"; // 给个默认的
            } else if (StringUtil.contains(error, "BASE64Decoder: Error in encoded stream:")) {
                log.warn("ReceiveMailUtil#getHtmlMailContent() error, e=" + e);
                return "系统: 邮件内容编码未支持 GET_HTML_MAIL_CONTENT_BASE64_DECODER_ERROR"; // 给个默认的
            } else {
                log.error("ReceiveMailUtil#getHtmlMailContent() error, e=" + e, e);
                return "系统: 邮件内容编码未支持 GET_HTML_MAIL_CONTENT_ERROR_ELSE"; // 给个默认的
            }
        }
    }

    private static boolean contentTypeHasName(String contentType) {
        int nameIndex = contentType.indexOf("name");
        return nameIndex != -1;
    }

    public static String htmlPartGetContent(Part part) {
        try {
            if (null == part) {
                log.error("htmlPartGetContent error, part is null");
                return null;
            }

            Object content = partGetContent(part);
            if (null != content) {
                if (content instanceof MimeMultipart) { // javax.mail.internet.MimeBodyPart
                    BodyPart bodyPart = ((MimeMultipart) content).getBodyPart(0);
                    return htmlPartGetContent(bodyPart); // 递归
                }

                return content.toString(); // 返回内容
            }

            log.error("htmlPartGetContent, error, part.type=" + part.getClass()); // com.sun.mail.imap.IMAPBodyPart
            return "系统: 邮件内容编码未支持, HTML_PART_GET_CONTENT_ELSE";
        } catch (Throwable e) {
            log.error("htmlPartGetContent, error, part.type=" + part.getClass() + ", error=" + e);
            return "系统: 邮件内容编码未支持, HTML_PART_GET_CONTENT_ERROR";
        }
    }

    /**
     * 替换掉原有的实现
     */
    private static Object partGetContent(Part part) {
        try {
            if (part instanceof MimeBodyPart) {
                return mimeBodyPartGetContent((MimeBodyPart) part);
            }

            return part.getContent();
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
    }

    private static Object mimeBodyPartGetContent(MimeBodyPart mimeBodyPart) throws MessagingException, IOException {
        String contentType = mimeBodyPart.getContentType();
        String language = getEncodingGb2312ToGbk(contentType); // gb2312 > gbk
        String encoding = mimeBodyPart.getEncoding();

        InputStream rawInputStream = mimeBodyPart.getRawInputStream();

        if (rawInputStream != null && encoding != null) { // 均不为空
            InputStream decodedInputStream = MimeUtility.decode(rawInputStream, encoding);
            InputStreamReader decodedInputStreamReader = new InputStreamReader(decodedInputStream, language);
            BufferedReader decodedBufferedReader = new BufferedReader(decodedInputStreamReader);
            String line = null;
            StringBuffer stringBuffer = new StringBuffer();
            while (null != (line = decodedBufferedReader.readLine())) {
                stringBuffer.append(line);
            }
            return stringBuffer.toString();
        } else if (rawInputStream != null) { //  encoding 为空
            log.info("mimeBodyPartGetContent error, encoding is null, " //
                    + " returning default, rawInputStream=" + rawInputStream + ", encoding=" + encoding);
            return mimeBodyPart.getContent();
        } else { // 均为空
            log.error("mimeBodyPartGetContent error, mimeBodyPart.getRawInputStream() is null and encoding is null, " //
                    + " returning default, rawInputStream=" + rawInputStream + ", encoding=" + encoding);
            return mimeBodyPart.getContent();
        }
    }

    private static String getEncodingGb2312ToGbk(String contentType) {
        String language = null;
        try {
            ContentType ct = new ContentType(contentType);
            language = ct.getParameter("charset");
        } catch (ParseException e) {
            log.error("getCharset error", e);
        }

        if (language == null) {
            language = MimeUtility.getDefaultJavaCharset();
        }
        if (language.equalsIgnoreCase("gb2312")) {
            language = "gbk";
        }
        return language;
    }

    private static String removeHtmlTagsByJsoup(String plainTextMailContent) {
        Document document = Jsoup.parse(plainTextMailContent);
        String documentText = document.text(); // jsoup 提取的文本

        int plainTextMailContentLen = StringUtil.length(StringUtil.trim(plainTextMailContent));
        int documentTextLen = StringUtil.length(StringUtil.trim(documentText));

        if (plainTextMailContentLen > documentTextLen) {
            return documentText; // 返回jsoup处理过的文本
        }

        return plainTextMailContent; // 返回邮件中取得的文本
    }
}